# Copyright (c) 2020 Presto Labs Pte. Ltd.
# Author: yuxuan

from collections import deque


class MovingOhlcBase(object):
  def __init__(self, timewindow):
    self._dq = deque()
    self._timewindow = timewindow

  def _update(self, ts):
    while self._dq and ts - self._dq[0][0] > self._timewindow:
      self._dq.popleft()

  def update(self, ts, data=None):
    raise NotImplementedError()

  def get(self):
    raise NotImplementedError()


class MovingHigh(MovingOhlcBase):
  def update(self, ts, data=None):
    self._update(ts)
    if data is not None:
      while self._dq and data >= self._dq[-1][1]:
        self._dq.pop()
      self._dq.append([ts, data])

  def get(self):
    if self._dq:
      return self._dq[0][1]
    return None


class MovingLow(MovingOhlcBase):
  def update(self, ts, data=None):
    self._update(ts)
    if data is not None:
      while self._dq and data <= self._dq[-1][1]:
        self._dq.pop()
      self._dq.append([ts, data])

  def get(self):
    if self._dq:
      return self._dq[0][1]
    return None


class MovingOpen(MovingOhlcBase):
  def update(self, ts, data=None):
    self._update(ts)
    if data is not None:
      self._dq.append([ts, data])

  def get(self):
    if self._dq:
      return self._dq[0][1]
    return None


class MovingClose(MovingOhlcBase):
  def __init__(self, timewindow):
    self._item = None
    self._ts = 0
    self._timewindow = timewindow

  def update(self, ts, data=None):
    if data:
      self._item = data
      self._ts = ts
    elif ts - self._ts > self._timewindow:
      self._item = None

  def get(self):
    return self._item
